use std::ops::{Add, Mul};
mod complex;

use complex::Complex as Complex;

fn main() {
    println!("Hello, world!");

    use std::fs::File;
        
    let mut file = File::create("foo.txt").unwrap();
    say_hello_write(&mut file).unwrap();

    let mut bytes = vec![];
    say_write(&mut bytes).unwrap();
    println!("{:?}", bytes);

    let str = String::from_utf8(bytes).unwrap();
    println!("{}", str);
    let str = str.replace("\n", "");
    println!("{}", str);
    let a = 1;
    let b = 2;
    let c = min(a, b);
    println!("min of {} and {} is {}", a, b, c);
    let a = 8;
    println!("fib {} = {}", a, fib::<f64>(a));
    let a:[i64; 4] = [1,2,3,4];
    let b:[i64; 4] = [5,6,7,8];
    println!("dot a {:?} * b {:?} = {}", a,b, dot(&a, &b));
    println!("dot2 a {:?} * b {:?} = {}", a, b, dot2::<i64>(&a, &b));
    let a= 1;
    let b = 2;
    println!("a + b = {}", a.add(b));
    let a = Complex::<f32> {
        re: 5.0, im :10.0
    };

    let b = Complex::<f32> { re: 20.0, im: 100.0 };
    println!("complex a +b ={:?}", a + b);

    println!("-a = {:?}", -a);
    let mut a = Complex::<f32> {
        re: 13.0, im : 20.0
    };
    a += b;
    println!("a+=b = {:?}", a);

}

// 特型的多态性表现 ，实现特型Write的多态性
fn say_hello_write(out :&mut dyn std::io::Write) -> std::io::Result<()> {
    out.write_all(b"Hello, world!\n")?;
    out.flush()
}

fn say_write<T: std::io::Write>(out: &mut T) -> std::io::Result<()> {
    out.write_all(b"Hello, world!\n")?;
    out.flush()
}


// it is a good practice to use the ? operator to propagate errors up the call stack.
// 泛型的多态性表现
fn min<T: Ord>(value1: T, value2: T) -> T {
    if value1 < value2 {
        value1
    } else {
        value2
    }
}

trait Float {
    const ZERO: Self;
    const ONE: Self;
}

impl Float for f32{
    const ZERO: f32 = 0.0;
    const ONE: f32 = 1.0;
}

impl Float for f64{
    const ZERO: f64 = 0.0;
    const ONE: f64 = 1.0;
}

fn fib<T: Float + Add<Output = T>>(f: usize) -> T {
    match f {
        0 => T::ZERO,
        1 => T::ONE,
        n => fib::<T>(n-1) + fib::<T>(n-2)
    }
}

fn dot(v1:&[i64], v2:&[i64]) ->i64 {
    let mut v :i64 = 0;
    for i in 0..v1.len() {
        v = v + v1[i]* v2[i];
    }
    v
}

fn dot2<T>(v1:&[T], v2:&[T]) -> T 
    where T : Add<Output = T> + Mul<Output = T> + Default + Copy
{
    let mut total: T = T::default();
    for v in 0..v1.len() {
        total = total + v1[v] * v2[v];
    }
    total
}


